use kvm_bindings::{
    __IncompleteArrayField, KVM_IRQCHIP_PIC_MASTER, KVM_IRQCHIP_PIC_SLAVE, KVM_MEM_LOG_DIRTY_PAGES,
    kvm_irq_routing_irqchip, kvm_irqchip, kvm_userspace_memory_region,
};
use kvm_ioctls::{Kvm, VcpuExit};

use std::{
    io::Write,
    ptr::null_mut,
    slice,
    sync::Arc,
    thread::{sleep, spawn},
    time::Duration,
};

fn main() {
    // 1. 初始化KVM并启用中断控制器
    let kvm = Kvm::new().unwrap();
    let vm = kvm.create_vm().unwrap();
    let vm = Arc::new(vm);
    vm.create_irq_chip().unwrap(); // 关键：启用PIC

    let mut irqchip = kvm_irqchip::default();
    irqchip.chip_id = KVM_IRQCHIP_PIC_MASTER;
    vm.get_irqchip(&mut irqchip).unwrap();
    unsafe {
        // println!("{:#x?}", irqchip.chip.pic);
        irqchip.chip.pic.elcr = 0b0000_0000;
        irqchip.chip.pic.elcr_mask = 0b1111_1111;
        irqchip.chip.pic.init4 = 0x1;
        irqchip.chip.pic.special_fully_nested_mode = 0;
        irqchip.chip.pic.rotate_on_auto_eoi = 0;
        irqchip.chip.pic.auto_eoi = 1;
        irqchip.chip.pic.init_state = 0b0000_1111;
        irqchip.chip.pic.special_mask = 0;
        irqchip.chip.pic.poll = 0;
        irqchip.chip.pic.read_reg_select = 0;
        irqchip.chip.pic.irq_base = 0b010_0000;
        irqchip.chip.pic.priority_add = 0;
        irqchip.chip.pic.imr = 0;
        vm.set_irqchip(&irqchip).unwrap();
    }

    let mut irqchip = kvm_irqchip::default();
    irqchip.chip_id = KVM_IRQCHIP_PIC_SLAVE;
    vm.get_irqchip(&mut irqchip).unwrap();
    unsafe {
        irqchip.chip.pic.elcr = 0b0000_0000;
        irqchip.chip.pic.elcr_mask = 0b1111_1111;
        irqchip.chip.pic.init4 = 0x1;
        irqchip.chip.pic.special_fully_nested_mode = 0;
        irqchip.chip.pic.rotate_on_auto_eoi = 0;
        irqchip.chip.pic.auto_eoi = 1;
        irqchip.chip.pic.init_state = 0b0000_1111;
        irqchip.chip.pic.special_mask = 0;
        irqchip.chip.pic.poll = 0;
        irqchip.chip.pic.read_reg_select = 0;
        irqchip.chip.pic.irq_base = 0b0010_1000;
        irqchip.chip.pic.priority_add = 0;
        irqchip.chip.pic.imr = 0;
        vm.set_irqchip(&irqchip).unwrap();
    }

    // 2. 设置内存区域
    let mem_size = 0x8000;

    let mem_ptr = unsafe {
        libc::mmap(
            null_mut(),
            mem_size,
            libc::PROT_READ | libc::PROT_WRITE,
            libc::MAP_ANONYMOUS | libc::MAP_SHARED,
            -1,
            0,
        ) as *mut u8
    };

    let mut mem = unsafe { slice::from_raw_parts_mut(mem_ptr, mem_size) };

    // 3. 加载代码
    let mem_region = kvm_userspace_memory_region {
        slot: 0,
        guest_phys_addr: 0,
        memory_size: mem_size as u64,
        userspace_addr: mem_ptr as u64,
        flags: KVM_MEM_LOG_DIRTY_PAGES,
    };
    unsafe {
        vm.set_user_memory_region(mem_region).unwrap();
    }

    let tmp_mem = include_bytes!("../img.out");
    mem.write_all(tmp_mem);

    let mut vcpu = vm.create_vcpu(0).unwrap();
    let mut regs = vcpu.get_regs().unwrap();
    regs.rip = 0x7c00;
    regs.rsp = 0x7000; //sti指令 启用中断

    vcpu.set_regs(&regs).unwrap();
    let mut sregs = vcpu.get_sregs().unwrap();
    sregs.cs.base = 0;
    sregs.cs.selector = 0;
    sregs.ds.base = 0;
    sregs.ds.selector = 0;
    sregs.es.base = 0;
    sregs.es.selector = 0;
    sregs.ss.base = 0;
    sregs.ss.selector = 0;
    vcpu.set_sregs(&sregs).unwrap();
    let arc_vm = vm.clone();
    spawn(move || {

        loop {
            for i in 0..16 {
                sleep(Duration::from_secs(1));
                if i == 2 {
                    println!("irq line is cacscade line to slave");
                    continue;
                }
                println!("set_irq_line {}",i);
                arc_vm.set_irq_line(i, true);
                sleep(Duration::from_millis(10));
                arc_vm.set_irq_line(i, false);
            }
        }
    });
    // 6. 运行虚拟机
    loop {
        match vcpu.run().unwrap() {
            VcpuExit::Hlt => {
                println!("Hlt");
                break;
            }
            VcpuExit::IoIn(_add, _d) => {
                println!("IoIn");
            }
            VcpuExit::IoOut(_add, _d) => {
                println!("IoOut");
            }
            VcpuExit::InternalError => {
                println!("InternalError");

                let r = vcpu.get_regs().unwrap();
                println!("{:#x?}", r);
            }
            VcpuExit::MmioWrite(add, d) => {
                println!("MmioWrite");
                println!("{add:#x} {d:#x?}");
                // let r = vcpu.get_regs().unwrap();
                // println!("{:#x?}", r);
            }
            VcpuExit::MmioRead(add, d) => {
                println!("MmioRead ");
                println!("{add:#x} {d:#x?}");
            }
            other => {
                println!("Unexpected exit: {:?}", other);

                break;
            }
        }
    }
}
